#!/usr/bin/env perl
# Author: csr
# Date：2016-01-15
# Email: chenshaorong@oschina.cn
# Version: v3.0
#
# 前提：经常会遇到这种情况：系统出问题了但是却找不出根源
# 该脚本则用于每n秒对比下，查看哪些进程发生了变化
#
# Tip: ctrl+c暂停，然后'q' or 'quit'退出(输入其他表示继续)
#
# 打印格式：
#   - 全：打印出两次所有不同进程的"pid ppid cmd"
#   - 1 : 打印前一次比后一次多的进程(通俗点讲就是这些进程消失了)
#   - 2 : 打印增加的进程
# 例如输入格式如下：
# csr@ubuntu:~$ ./ps_diff.pl n
# 补集-全
#  7189 6375     /bin/sleep 10
# 补集-1
# 补集-2
#  7189 6375     /bin/sleep 10

# 拓展1：显示绝对路径
# 拓展2:
#   - 对于以下输出应该改进 (频繁变化的子进程应该归类成一类，只输入父进程，然后需要的时候再查看其子进程)
#   - 对于进程、线程的hash比较不应该把"server: configuration..."这后面的也算进去，但是输出时需要这个详细结果
# 补集-1
#  8139 8137     /usr//sbin/zabbix_server: configuration syncer [synced configuration in 0.013953 sec, idle 60 sec]
# 补集-2
#  8139 8137     /usr//sbin/zabbix_server: configuration syncer [synced configuration in 0.013934 sec, idle 60 sec]

#use strict;
use warnings;

sub sig_handler {
    chomp(my $in=<STDIN>);
	#die $! if $in eq 'quit';
    exit 0 if $in eq 'quit' || $in eq 'q';
}

$SIG{INT}=\&sig_handler;

system("clear");

# 默认间隔时间等于10s
our $seq=10;
# 判断$1是否为合法数字且大于0
$seq=$ARGV[0] if 0 < @ARGV && $ARGV[0] =~ /^-?\d+(\.\d+)?$/ && $ARGV[0] !~ /^-?0(\d+)?$/ && $ARGV[0] > 0;

our @res1=`ps -ef |awk -F' ' '{if(\$2!='$$' && \$3!=$$ && \$2!='\$\$' && \$3!='\$\$'){\$1=\$4=\$5=\$6=\$7=""; print}}'`;
#our %m, %n, @res2;
our %m;
our %n;
our @res2;

while(1){
    sleep $seq;
    system("clear");
    @res2=`ps -ef |awk -F' ' '{if(\$2!='$$' && \$3!=$$ && \$2!='\$\$' && \$3!='\$\$'){\$1=\$4=\$5=\$6=\$7=""; print}}'`;
    
    # 并集、交集
    for(@res1,@res2){
        $m{$_}++ && $n{$_}++;
    }
    #@binji=keys %m; # 0 1 2
    #@union=keys %n; # 0 1
    
    # 补集-全
    print "补集-全\n";
    foreach(keys %m){
        print unless (exists($n{$_}) && $n{$_}==1);
    }
    
    # 补集-1
    print "补集-1\n";
    foreach(@res1){
        print unless (exists($n{$_}) && $n{$_}==1);
    }
    
    # 补集-2
    print "补集-2\n";
    foreach(@res2){
        print unless (exists($n{$_}) && $n{$_}==1);
    }

    %m=();
    %n=();
    @res1=@res2;
}
